namespace Creek.UI.PropertyGridEx
{
    using System;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;

    public class UIListboxEditor : UITypeEditor
    {
        private readonly ListBox oList = new ListBox();

        private bool bIsDropDownResizable;

        private IWindowsFormsEditorService oEditorService;

        private object oSelectedValue;

        public override bool IsDropDownResizable
        {
            get
            {
                return this.bIsDropDownResizable;
            }
        }

        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            if (context != null && context.Instance != null)
            {
                var attribute =
                    (UIListboxIsDropDownResizable)
                    context.PropertyDescriptor.Attributes[typeof(UIListboxIsDropDownResizable)];
                if (attribute != null)
                {
                    this.bIsDropDownResizable = true;
                }
                return UITypeEditorEditStyle.DropDown;
            }
            return UITypeEditorEditStyle.None;
        }

        [RefreshProperties(RefreshProperties.All)]
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            if (context == null || provider == null || context.Instance == null)
            {
                return base.EditValue(provider, value);
            }

            this.oEditorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (this.oEditorService != null)
            {
                // Get the Back reference to the Custom Property
                var oDescriptor = (CustomProperty.CustomPropertyDescriptor)context.PropertyDescriptor;
                var cp = (CustomProperty)oDescriptor.CustomProperty;

                // Declare attributes
                UIListboxDatasource datasource;
                UIListboxValueMember valuemember;
                UIListboxDisplayMember displaymember;

                // Get attributes
                datasource = (UIListboxDatasource)context.PropertyDescriptor.Attributes[typeof(UIListboxDatasource)];
                valuemember = (UIListboxValueMember)context.PropertyDescriptor.Attributes[typeof(UIListboxValueMember)];
                displaymember =
                    (UIListboxDisplayMember)context.PropertyDescriptor.Attributes[typeof(UIListboxDisplayMember)];

                this.oList.BorderStyle = BorderStyle.None;
                this.oList.IntegralHeight = true;

                if (datasource != null)
                {
                    this.oList.DataSource = datasource.Value;
                }

                if (displaymember != null)
                {
                    this.oList.DisplayMember = displaymember.Value;
                }

                if (valuemember != null)
                {
                    this.oList.ValueMember = valuemember.Value;
                }

                if (value != null)
                {
                    if (value.GetType().Name == "String")
                    {
                        this.oList.Text = (string)value;
                    }
                    else
                    {
                        this.oList.SelectedItem = value;
                    }
                }

                this.oList.SelectedIndexChanged += this.SelectedItem;

                this.oEditorService.DropDownControl(this.oList);
                if (this.oList.SelectedIndices.Count == 1)
                {
                    cp.SelectedItem = this.oList.SelectedItem;
                    cp.SelectedValue = this.oSelectedValue;
                    value = this.oList.Text;
                }
                this.oEditorService.CloseDropDown();
            }
            else
            {
                return base.EditValue(provider, value);
            }

            return value;
        }

        private void SelectedItem(object sender, EventArgs e)
        {
            if (this.oEditorService != null)
            {
                if (this.oList.SelectedValue != null)
                {
                    this.oSelectedValue = this.oList.SelectedValue;
                }
                this.oEditorService.CloseDropDown();
            }
        }

        #region Nested type: UIListboxDatasource

        [AttributeUsage(AttributeTargets.Property)]
        public class UIListboxDatasource : Attribute
        {
            private readonly object oDataSource;

            public UIListboxDatasource(ref object Datasource)
            {
                this.oDataSource = Datasource;
            }

            public object Value
            {
                get
                {
                    return this.oDataSource;
                }
            }
        }

        #endregion

        #region Nested type: UIListboxDisplayMember

        [AttributeUsage(AttributeTargets.Property)]
        public class UIListboxDisplayMember : Attribute
        {
            public UIListboxDisplayMember(string DisplayMember)
            {
                this.Value = DisplayMember;
            }

            public string Value { get; set; }
        }

        #endregion

        #region Nested type: UIListboxIsDropDownResizable

        [AttributeUsage(AttributeTargets.Property)]
        public class UIListboxIsDropDownResizable : Attribute
        {
        }

        #endregion

        #region Nested type: UIListboxValueMember

        [AttributeUsage(AttributeTargets.Property)]
        public class UIListboxValueMember : Attribute
        {
            public UIListboxValueMember(string ValueMember)
            {
                this.Value = ValueMember;
            }

            public string Value { get; set; }
        }

        #endregion
    }
}